home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
FSTRUCT.C
< prev
next >
Wrap
Text File
|
1990-03-02
|
14KB
|
629 lines
/*
* File: fstruct.c
* Contents: delete, get, key, insert, list, member, pop, pull, push, put, set,
* table
*/
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#ifdef PreProcess
/* include(../M4/fncs.m4) /* */
/* */
#endif /* PreProcess */
/*
* delete(X,x) - delete element x from set or table X if it is there
* (always succeeds and returns X).
*/
FncDcl(delete,2)
{
register union block **pd;
register uword hn;
int res;
if (Qual(Arg1))
RunErr(122, &Arg1);
/*
* The technique and philosophy here are the same
* as used in insert - see comment there.
*/
switch (Type(Arg1)) {
case T_Set:
case T_Table:
hn = hash(&Arg2);
pd = memb(BlkLoc(Arg1), &Arg2, hn, &res);
if (res == 1) {
/*
* The element is there so delete it.
*/
*pd = (*pd)->selem.clink;
(BlkLoc(Arg1)->set.size)--;
}
break;
default:
RunErr(122, &Arg1);
}
Arg0 = Arg1;
Return;
}
/*
* get(x) - get an element from end of list x.
* Identical to pop(x).
*/
FncDcl(get,1)
{
register word i;
register struct b_list *hp;
register struct b_lelem *bp;
/*
* Arg1 must be a list.
*/
if (Arg1.dword != D_List)
RunErr(108, &Arg1);
/*
* Fail if the list is empty.
*/
hp = (struct b_list *) BlkLoc(Arg1);
if (hp->size <= 0)
Fail;
/*
* Point bp at the first list block. If the first block has no
* elements in use, point bp at the next list block.
*/
bp = (struct b_lelem *) hp->listhead;
if (bp->nused <= 0) {
bp = (struct b_lelem *) bp->listnext;
hp->listhead = (union block *) bp;
bp->listprev = NULL;
}
/*
* Locate first element and assign it to Arg0 for return.
*/
i = bp->first;
Arg0 = bp->lslots[i];
/*
* Set bp->first to new first element, or 0 if the block is now
* empty. Decrement the usage count for the block and the size
* of the list.
*/
if (++i >= bp->nslots)
i = 0;
bp->first = i;
bp->nused--;
hp->size--;
Return;
}
/*
* key(t) - generate successive keys (entry values) from table t.
*/
FncDcl(key,2)
{
if (Arg1.dword != D_Table)
RunErr(124, &Arg1);
MakeInt(1, &Arg2); /* indicate that we want the keys */
Forward(hgener); /* go to the hash generator */
}
/*
* insert(X,x) - insert element x into set or table X if not already there
* (always succeeds and returns X).
*/
FncDcl(insert,3)
{
register union block *bp;
register union block **pd;
register struct b_telem *pe;
register uword hn;
int res;
if (Qual(Arg1))
RunErr(122, &Arg1);
switch (Type(Arg1)) {
case T_Set:
/*
* We may need at most one new element.
*/
if (blkreq((word)sizeof(struct b_selem)) == Error)
RunErr(0, NULL);
bp = BlkLoc(Arg1);
hn = hash(&Arg2);
/*
* If Arg2 is a member of set Arg1 then res will have the
* value 1 and pd will have a pointer to the pointer
* that points to that member.
* If Arg2 is not a member of the set then res will have
* the value 0 and pd will point to the pointer
* which should point to the member - thus we know where
* to link in the new element without having to do any
* repetitive looking.
*/
pd = memb(bp, &Arg2, hn, &res);
if (res == 0) {
/*
* The element is not in the set - insert it.
*/
addmem((struct b_set *)bp, alcselem(&Arg2, hn), pd);
if (TooCrowded(bp))
hgrow(&Arg1);
}
break;
case T_Table:
if (blkreq((word)sizeof(struct b_telem)) == Error)
RunErr(0, NULL);
bp = BlkLoc(Arg1);
hn = hash(&Arg2);
pd = memb(bp, &Arg2, hn, &res);
if (res == 0) {
/*
* The element is not in the table - insert it.
*/
bp->table.size++;
pe = alctelem();
pe->clink = *pd;
*pd = (union block *)pe;
pe->hashnum = hn;
pe->tref = Arg2;
pe->tval = Arg3;
if (TooCrowded(bp))
hgrow(&Arg1);
}
else {
pe = (struct b_telem *) *pd;
pe->tval = Arg3;
}
break;
default:
RunErr(122, &Arg1);
}
Arg0 = Arg1;
Return;
}
/*
* list(n,x) - create a list of size n, with initial value x.
*/
FncDcl(list,2)
{
register word i, size;
word nslots;
register struct b_list *hp;
register struct b_lelem *bp;
if (defshort(&Arg1, 0) == Error)
RunErr(0, NULL);
nslots = size = IntVal(Arg1);
/*
* Ensure that the size is positive and that the list-element block
* has MinListSlots slots if its size is zero.
*/
if (size < 0)
RunErr(205, &Arg1);
if (nslots == 0)
nslots = MinListSlots;
/*
* Ensure space for a list-header block, and a list-element block
* with nslots slots.
*/
if (blkreq(sizeof(struct b_list) + sizeof(struct b_lelem) +
(nslots - 1) * sizeof(struct descrip)) == Error)
RunErr(0, NULL);
/*
* Allocate the list-header block and a list-element block.
* Note that nslots is the number of slots in the list-element
* block while size is the number of elements in the list.
*/
hp = alclist(size);
bp = alclstb(nslots, (word)0, size);
hp->listhead = hp->listtail = (union block *) bp;
/*
* Initialize each slot.
*/
for (i = 0; i < size; i++)
bp->lslots[i] = Arg2;
/*
* Return the new list.
*/
Arg0.dword = D_List;
BlkLoc(Arg0) = (union block *) hp;
Return;
}
/*
* member(X,x) - returns x if x is a member of set or table X otherwise fails.
*/
FncDcl(member,2)
{
int res;
register uword hn;
if (Qual(Arg1))
RunErr(122, &Arg1);
switch (Type(Arg1)) {
case T_Set:
case T_Table:
hn = hash(&Arg2);
memb(BlkLoc(Arg1), &Arg2, hn, &res);
break;
default:
RunErr(122, &Arg1);
}
/* If Arg2 is a member of Arg1 then "res" will have the
* value 1 otherwise it will have the value 0.
*/
if (res == 1) { /* It is a member. */
Arg0 = Arg2; /* Return the member if it is in Arg1. */
Return;
}
Fail;
}
/*
* pop(x) - pop an element from beginning of list x.
*/
FncDcl(pop,1)
{
register word i;
register struct b_list *hp;
register struct b_lelem *bp;
/*
* Arg1 must be a list.
*/
if (Arg1.dword != D_List)
RunErr(108, &Arg1);
/*
* Fail if the list is empty.
*/
hp = (struct b_list *) BlkLoc(Arg1);
if (hp->size <= 0)
Fail;
/*
* Point bp to the first list-element block. If the first block has
* no slots in use, point bp at the next list-element block.
*/
bp = (struct b_lelem *) hp->listhead;
if (bp->nused <= 0) {
bp = (struct b_lelem *) bp->listnext;
hp->listhead = (union block *) bp;
bp->listprev = NULL;
}
/*
* Locate first element and assign it to Arg0 for return.
*/
i = bp->first;
Arg0 = bp->lslots[i];
/*
* Set bp->first to new first element, or 0 if the block is now
* empty. Decrement the usage count for the block and the size
* of the list.
*/
if (++i >= bp->nslots)
i = 0;
bp->first = i;
bp->nused--;
hp->size--;
Return;
}
/*
* pull(x) - pull an element from end of list x.
*/
FncDcl(pull,1)
{
register word i;
register struct b_list *hp;
register struct b_lelem *bp;
/*
* Arg1 must be a list.
*/
if (Arg1.dword != D_List)
RunErr(108, &Arg1);
/*
* Point at list header block and fail if the list is empty.
*/
hp = (struct b_list *) BlkLoc(Arg1);
if (hp->size <= 0)
Fail;
/*
* Point bp at the last list element block. If the last block has no
* elements in use, point bp at the previous list element block.
*/
bp = (struct b_lelem *) hp->listtail;
if (bp->nused <= 0) {
bp = (struct b_lelem *) bp->listprev;
hp->listtail = (union block *) bp;
bp->listnext = NULL;
}
/*
* Set i to position of last element and assign the element to
* Arg0 for return. Decrement the usage count for the block
* and the size of the list.
*/
i = bp->first + bp->nused - 1;
if (i >= bp->nslots)
i -= bp->nslots;
Arg0 = bp->lslots[i];
bp->nused--;
hp->size--;
Return;
}
/*
* push(x,val) - push val onto beginning of list x.
*/
FncDcl(push,2)
{
register word i;
register struct b_list *hp;
register struct b_lelem *bp;
static two = 2; /* some compilers generat bad code for
division by a constant that's a power of 2 */
/*
* Arg1 must be a list.
*/
if (Arg1.dword != D_List)
RunErr(108, &Arg1);
/*
* Point hp at the list-header block and bp at the first
* list-element block.
*/
hp = (struct b_list *) BlkLoc(Arg1);
bp = (struct b_lelem *) hp->listhead;
/*
* If the first list-element block is full, allocate a new
* list-element block, make it the first list-element block,
* and make it the previous block of the former first list-element
* block.
*/
if (bp->nused >= bp->nslots) {
/*
* Set i to the size of block to allocate.
*/
i = hp->size / two;
if (i < MinListSlots)
i = MinListSlots;
/*
* Ensure space for a new list element block. If the block can't
* be allocated, try smaller blocks.
*/
while (blkreq((word)sizeof(struct b_lelem) +
i * sizeof(struct descrip)) == Error) {
i /= 4;
if (i < MinListSlots)
RunErr(0, NULL);
}
/*
* Reset hp in case there was a garbage collection.
*/
hp = (struct b_list *) BlkLoc(Arg1);
bp = alclstb(i, (word)0, (word)0);
hp->listhead->lelem.listprev = (union block *) bp;
bp->listnext = hp->listhead;
hp->listhead = (union block *) bp;
}
/*
* Set i to position of new first element and assign val (Arg2) to
* that element.
*/
i = bp->first - 1;
if (i < 0)
i = bp->nslots - 1;
bp->lslots[i] = Arg2;
/*
* Adjust value of location of first element, block usage count,
* and current list size.
*/
bp->first = i;
bp->nused++;
hp->size++;
/*
* Return the list.
*/
Arg0 = Arg1;
Return;
}
/*
* put(x,val) - put val onto end of list x.
*/
FncDcl(put,2)
{
register word i;
register struct b_list *hp;
register struct b_lelem *bp;
static two = 2; /* some compilers generate bad code for
division by a constant that's a power of 2 */
/*
* Arg1 must be a list.
*/
if (Arg1.dword != D_List)
RunErr(108, &Arg1);
/*
* Point hp at the list-header block and bp at the last
* list-element block.
*/
hp = (struct b_list *) BlkLoc(Arg1);
bp = (struct b_lelem *) hp->listtail;
/*
* If the last list-element block is full, allocate a new
* list-element block, make it the first list-element block,
* and make it the next block of the former last list-element
* block.
*/
if (bp->nused >= bp->nslots) {
/*
* Set i to the size of block to allocate.
*/
i = hp->size / two;
if (i < MinListSlots)
i = MinListSlots;
/*
* Ensure space for a new list element block. If the block can't
* be allocated, try smaller blocks.
*/
while (blkreq((word)sizeof(struct b_lelem) +
i * sizeof(struct descrip)) == Error) {
i /= 4;
if (i < MinListSlots)
RunErr(0, NULL);
}
/*
* Reset hp in case there was a garbage collection.
*/
hp = (struct b_list *) BlkLoc(Arg1);
bp = alclstb(i, (word)0, (word)0);
hp->listtail->lelem.listnext = (union block *) bp;
bp->listprev = hp->listtail;
hp->listtail = (union block *) bp;
}
/*
* Set i to position of new last element and assign Arg2 to
* that element.
*/
i = bp->first + bp->nused;
if (i >= bp->nslots)
i -= bp->nslots;
bp->lslots[i] = Arg2;
/*
* Adjust block usage count and current list size.
*/
bp->nused++;
hp->size++;
/*
* Return the list.
*/
Arg0 = Arg1;
Return;
}
/*
* set(list) - create a set with members in list.
* The members are linked into hash chains which are
* arranged in increasing order by hash number.
*/
FncDcl(set,1)
{
register uword hn;
register dptr pd;
register union block *ps, *pb;
struct b_selem *ne;
union block **pe;
int res;
word i, j;
if (ChkNull(Arg1)) { /* Create empty set */
ps = hmake(T_Set, (word)0, (word)0);
if (ps == NULL)
RunErr(0,NULL);
Arg0.dword = D_Set;
BlkLoc(Arg0) = ps;
Return;
}
if (Arg1.dword != D_List)
RunErr(108, &Arg1);
/*
* Make a set of the appropriate size.
*/
ps = hmake(T_Set, (word)0, BlkLoc(Arg1)->list.size);
if (ps == NULL)
RunErr(0, NULL);
/*
* Chain through each list block and for
* each element contained in the block
* insert the element into the set if not there.
*/
for (pb = BlkLoc(Arg1)->list.listhead; pb != NULL; pb = pb->lelem.listnext) {
for (i = 0; i < pb->lelem.nused; i++) {
j = pb->lelem.first + i;
if (j >= pb->lelem.nslots)
j -= pb->lelem.nslots;
pd = &pb->lelem.lslots[j];
pe = memb(ps, pd, hn = hash(pd), &res);
if (res == 0) {
ne = alcselem(pd,hn);
addmem((struct b_set *)ps, ne, pe);
}
}
}
Arg0.dword = D_Set;
BlkLoc(Arg0) = ps;
Return;
}
/*
* table(x) - create a table with default value x.
*/
FncDcl(table,1)
{
union block *bp;
bp = hmake(T_Table, (word)0, (word)0);
if (bp == NULL)
RunErr(0, NULL);
bp->table.defvalue = Arg1;
Arg0.dword = D_Table;
BlkLoc(Arg0) = bp;
Return;
}